今天我們要來學如何建立Web API
,並利用Postman
進行API的測試,最後安裝Swagger
套件來產生API的說明文件。
與WebService相比,API可以在header帶token
進行驗證、並鎖CORS
、限制IP或domain,較WebService有較多的防護。
不過對於資安的議題除了在前端可以做第一層防護限制格式的輸入
、上傳檔案重新命名存檔
、驗證從API接進來的資料格式
,在程式撰寫部分最基本的就是不要造成 SQL Injection
,並做第二次的輸入格式驗證;軟硬體要做好 內外網分離
將網站放在DMZ區、系統更新
、弱點掃描
、異地備份
、災難復原演練
等方式,資安議題一定會一直存在,只能把該做的事情做好,對於最差的情況就是能快速復原系統 (不考慮資料洩漏的部分)。
講太多廢話了,我們回來開始學如何建立Web API!
Web API不是像我們網頁使用的Webfrom模式,而是類似MVC架構(Model-View–Controller),只是沒有View而已。
參考維基百科,MVC架構說明如下:
模型(Model)
- 程式設計師編寫程式應有的功能(實現演算法等等)、資料庫專家進行資料管理和資料庫設計(可以實現具體的功能)。視圖(View)
- 介面設計人員進行圖形介面設計。控制器(Controller)
- 負責轉發請求,對請求進行處理。
參考微軟官方文件:ASP.NET Identity 簡介
STEP 1. 首先,先建立一個ASP.NET Web應用程式
STEP 2. 設定專案名稱OLMapAPI
和路徑,選擇.NET版本
STEP 3. 選擇建立Web API
,並於右上角的 驗證
選擇 個別使用者帳戶
驗證,這種驗證方法可以藉由Register 來進行個別帳號的註冊,並透過 ASP.NET Identity
將帳號與加密後的密碼儲存在SQL Server資料表當中。
STEP 4. 更改Web.config內的資料庫連線字串,這部分我們在 Day 11 建立WebService時有學過。
<add name="DefaultConnection" connectionString="Data Source=localhost\SQLEXPRESS;Initial Catalog=OLDemo; user id=資料庫帳號;password=資料庫密碼" providerName="System.Data.SqlClient" />
這邊可以將 name="DefaultConnection"
改掉,但由於我們使用 Identity.EntityFramework
來進行帳號的儲存,因此若要將Default改掉,則在 IdentityModels.cs
這個頁面 的base("DefaultConnection", throwIfV1Schema: false)
字串也要改掉。 (本系列講解API的部分暫時維持 "DefaultConnection")
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext()
: base("DefaultConnection", throwIfV1Schema: false)
{
}
public static ApplicationDbContext Create()
{
return new ApplicationDbContext();
}
}
STEP 5. 在Models下新增 BasicModels.cs
程式碼頁面
STEP 6. 在 BasicModels.cs
內新增 LayerResourceList
的類別,為圖層資料的輸出類別。
public class LayerResourceList
{
public string ID { get; set; }
public string GroupID { get; set; }
public string GroupName { get; set; }
public string LayerID { get; set; }
public string LayerOrder { get; set; }
public string LayerQueryable { get; set; }
public string LayerTitle { get; set; }
public string LayerType { get; set; }
public string DataType { get; set; }
public string DataURL { get; set; }
public string LayerVisibleCode { get; set; }
public string OpenOpacity { get; set; }
}
STEP 5. (新增) Infrastructure\BasicInfo
資料夾底下新增BasicInfoFunc.cs
,並將從資料庫撈取資料的程式碼 getLayerResourceList()
寫在這支裡面:
using System;
using System.Collections.Generic;
using OLMapAPI.Models;
using System.Data;
using System.Configuration;
using System.Data.SqlClient;
using OLMapAPI.Models.auth;
using System.Threading.Tasks;
namespace OLMapAPI.Infrastructure.BasicInfo
{
public class BasicInfoFunc
{
public static async Task<List<LayerResourceList>> getLayerResourceList()
{
SqlDataReader dr = null;
SqlConnection myConnection = new SqlConnection();
string Constr = ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString;
myConnection.ConnectionString = Constr;
SqlCommand sqlCmd = new SqlCommand();
string sqlStr;
sqlStr = "SELECT [ID] ,[GroupID] ,[GroupName] ,[LayerID] ,[LayerOrder] ,[LayerQueryable] ,[LayerTitle] ,[LayerType],[DataType] ,[DataURL] ,[LayerVisibleCode] ,[OpenOpacity] FROM [OLDemo].[dbo].[LayerResource] order by [GroupID], [LayerOrder], [LayerType]";
sqlCmd.CommandText = sqlStr;
sqlCmd.CommandType = CommandType.Text;
sqlCmd.Connection = myConnection;
List<LayerResourceList> arrList = new List<LayerResourceList>();
try
{
myConnection.Open();
dr = sqlCmd.ExecuteReader();
while (dr.Read())
{
arrList.Add(new LayerResourceList()
{
ID = dr["ID"].ToString(),
GroupID = dr["GroupID"].ToString(),
GroupName = dr["GroupName"].ToString(),
LayerID = dr["LayerID"].ToString(),
LayerOrder = dr["LayerOrder"].ToString(),
LayerQueryable = dr["LayerQueryable"].ToString(),
LayerTitle = dr["LayerTitle"].ToString(),
LayerType = dr["LayerType"].ToString(),
DataType = dr["DataType"].ToString(),
DataURL = dr["DataURL"].ToString(),
LayerVisibleCode = dr["LayerVisibleCode"].ToString(),
OpenOpacity = dr["OpenOpacity"].ToString()
});
}
myConnection.Close();
myConnection.Dispose();
return arrList;
}
catch (Exception ex)
{
throw;
}
}
};
}
STEP 6. 在Controllers
資料夾底下新增LayersController.cs
,具有讀取/寫入動作的MVC 5 控制器,也可以新增空白的自己刻。
STEP 7. 在Controller內新增 getLayerResource()
功能
using OLMapAPI.Infrastructure.BasicInfo;
using OLMapAPI.Models;
using Swashbuckle.Swagger.Annotations;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using System.Web.Http;
namespace OLMapAPI.Controllers
{
//[Authorize]
[RoutePrefix("api/Layers")]
public class LayersController : ApiController
{
[Route("getLayerResource")]
[HttpGet]
public async Task<HttpResponseMessage> getLayerResource()
{
try
{
return Request.CreateResponse(HttpStatusCode.OK, await BasicInfoFunc.getLayerResourceList());
}
catch (Exception SqlException)
{
return Request.CreateResponse(HttpStatusCode.InternalServerError, "Internal Server Error");
}
}
}
}
將api架在IIS上:http://localhost/OLMapAPI
STEP 1. 安裝 postman
STEP 2. 輸入API資料:
輸出 (截部分)
[
{
"ID": "1",
"GroupID": "nlsc",
"GroupName": "國土測繪中心",
"LayerID": "nlsc_school",
"LayerOrder": "1",
"LayerQueryable": "False",
"LayerTitle": "各級學校範圍圖",
"LayerType": "Tile",
"DataType": "WMS",
"DataURL": "https://wms.nlsc.gov.tw/wms",
"LayerVisibleCode": "SCHOOL",
"OpenOpacity": "0"
},
{
"ID": "5",
"GroupID": "opendata",
"GroupName": "OpenData",
"LayerID": "DebrisArea_geojson",
"LayerOrder": "1",
"LayerQueryable": "False",
"LayerTitle": "土石流潛勢溪流影響範圍圖",
"LayerType": "Vector",
"DataType": "GeoJSON",
"DataURL": "data/GeoJSON",
"LayerVisibleCode": "DebrisArea.Geojson",
"OpenOpacity": "0"
}
]
STEP 3. 圖台部分於 init.js
新增Api路徑
var config_OLMapWebAPI = "http://localhost/OLMapAPI/api";
STEP 4. 修正 jTOC.js
的介接ajax內容,修正後:
//修正後
$.ajax({
//type: "POST",
//url: config_WSLayerResource + "/getLayerResource",
type: "GET",
url: config_OLMapWebAPI + "/Layers/getLayerResource",
dataType: "json",
contentType: "application/json; charset=utf-8",
success: function (d) {
//var data = $.parseJSON(d.d);
var data = d;
console.log(data);
var layerlisthtml = "";
TOCArray = [];
$.each(data, function (index, item) {
loadLayer(item);
if (typehasExtent.includes(item.DataType)) {
layerlisthtml += '<div class="item"><div class="ui checkbox"><input type="checkbox" name="example" onclick="toc.toggleTocLayer(\'' + item.LayerID + '\', this)"><label></label></div><div class="content"><a class="header">' + item.LayerTitle + '</a><div class="description">' + item.DataType + '</div><img class="layerBtns info" src="images/TOCpage/info.png" title="點擊定位圖層" onclick="toc.zoomTocLayer(\'' + item.LayerID + '\')"></div></div>';
} else {
layerlisthtml += '<div class="item"><div class="ui checkbox"><input type="checkbox" name="example" onclick="toc.toggleTocLayer(\'' + item.LayerID + '\', this)"><label></label></div><div class="content"><a class="header">' + item.LayerTitle + '</a><div class="description">' + item.DataType + '</div></div></div>';
}
TOCArray.push(item);
});
$("#layerlist").html(layerlisthtml);
},
error: function (jqXHR, exception) {
ajaxError(jqXHR, exception);
}
});
STEP 5. 測試網站執行
測試成功!!
STEP 1. 使用 工具> NuGet套件管理員> 管理方案的NuGet套件下
安裝 Swashbuckle
套件。
STEP 2. 進行專案 XML 註解設定,會在 App_Data
資料夾下產生XML文件
STEP 3. 在 Controller 方法加上註解,按下 "///" 會自動產生 Comment
/// <summary>
/// 查詢所有圖層資料
/// </summary>
/// <returns></returns>
[Route("getLayerResource")]
[HttpGet]
[SwaggerResponse(HttpStatusCode.OK, "OK", typeof(List<LayerResourceList>))]
public async Task<HttpResponseMessage> getLayerResource()
{
try
{
return Request.CreateResponse(HttpStatusCode.OK, await BasicInfoFunc.getLayerResourceList());
}
catch (Exception SqlException)
{
return Request.CreateResponse(HttpStatusCode.InternalServerError, "Internal Server Error");
}
}
STEP 4. 設定 SwaggerConfig.cs 搜尋 IncludeXmlComments
> 將此行反註解
STEP 5. 註解拿掉後會發現缺少 GetXmlCommentsPath
方法,也就是專案檔設定的 XML 路徑
直接在底下新增下面幾行:
private static string GetXmlCommentsPath() {
return String.Format(
@ "{0}\App_Data\XmlDocument.xml",
AppDomain.CurrentDomain.BaseDirectory);
}
STEP 6. 將專案起始頁指定為swagger
STEP 7. 建置後IIS架站,看到swagger頁面就完成拉!
參考文章:https://marcus116.blogspot.com/2019/01/how-to-add-api-document-using-swagger-in-webapi.html
如同標題所說,我們今天學會了怎麼建Web API、學會了怎麼用Postman測試,最後學會了怎麼套用Swagger產生api說明文件,也就是說一個簡單的API就這樣完成拉!!!
但身為一個API只有這些功能還不夠,只少要能夠進行帳號驗證、權限控管,讓有權限的人才可以使用這個圖台,並在每次撈取檔案的時候就再進行一次身分確認,增加系統的安全性,所以後面的幾天我們就要來講 Web API的權限控管機制的建立
,可能會稍微複雜,要有心理準備!